/******************************************************************************
	This file is a part of the Snapshot Bioinformatics Project

	Copyright (C) 2012-2013 Jarom Schow

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#ifndef SQL_SERVER_H
#define SQL_SERVER_H

#include "BioDefs.h"

#include <QtCore/QStringList>
#include <QtCore/QHash>
#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlQuery>

namespace Bio {

class SeqDatabase;
class Sequence;
class SeqRange;
class SeqRecord;
class SqlServer;
class Taxon;

class BIO_EXPORT SqlServerSettings {
	friend class SqlServer;
public:

	enum ServerType { PostgreSQL = 0, MySQL, MySQLEmbedded, Unknown };

	SqlServerSettings();
	SqlServerSettings( const QString &configFile, const QString &dbname );
	SqlServerSettings( ServerType type, const QString &host, int port, const QString &user, const QString &pass, const QString &dbname );
	SqlServerSettings( const SqlServerSettings &settings );
	~SqlServerSettings();

	SqlServerSettings&	operator=( const SqlServerSettings &settings );

	bool		isValid() const;

	void		setServerType( ServerType type );
	ServerType	getServerType() const;

	void	setHostName( const QString &host );
	QString	getHostName() const;

	void	setPort( int port );
	int		getPort() const;

	void	setUserName( const QString &name );
	QString	getUserName() const;

	void	setPassword( const QString &pass );
	QString	getPassword() const;

	void	setDatabaseName( const QString &configFile );
	QString	getDatabaseName() const;

	void	setConfigurationFile( const QString &name );
	QString	getConfigurationFile() const;

private:

	int			m_port;
	QString		m_host, m_user, m_password, m_dbname, m_configFile;
	ServerType	m_type;
};

class BIO_EXPORT SqlServer {
public:
	SqlServer();
	SqlServer( const SqlServerSettings &settings );
	~SqlServer();

	bool	isConnected() const;
	bool	connect( const SqlServerSettings &settings );
	void	close();

	bool	create( const SqlServerSettings &settings );

	bool	updateTaxonomy( const QString &tempDir = QString::null );

	const QSqlDatabase&	getDatabase() const;

	QStringList	getSeqDatabaseNames() const;
	SeqDatabase	getSeqDatabase( const QString &name ) const;
	bool		createSeqDatabase( const QString &name, const QString &authority, const QString &description );

	int		getOntologyId( const QString &name );
	int		getTermId( const QString &term, const QString &ontology );
	int		getTermId( const QString &term, int ontologyId );

	SeqRange	getFeatureRange( int seqFeatureId );

	bool	exec( const QString &sql );

	bool	startTransaction();
	bool	commit();
	bool	rollback();

	QSqlQuery	getQuery() const;

	QString		getLastError() const;

	QString		esc( const QString &str, bool emptyAsNull = false ) const;

	SeqRecord	getRecord( int bioentryId, int seqDatabaseId = -1 );
	SeqRecord	getRecordByAccession( const QString &accession, int seqDatabaseId = -1 );

	QList<SeqRecord>	getRecordsForTaxon( int taxonId, int seqDatabaseId = -1 );

	Sequence*	getSequence( int bioentryId );

	bool	createUser( const QString &userName, const QString &password = QString::null, bool grantAll = false );

private:

	bool	connect();
	bool	create();

	int		addOntology( const QString &name, const QString &definition );
	int		addTerm( const QString &term, int ontologyId, const QString &definition, const QString &identifier );
	void	setError( const QString &msg );
	bool	createPostgre();
	bool	createMySQL();

	SeqRecord	getRecord( const QString &condition );
	SeqRecord	makeRecord( const QSqlQuery &result );

	QSqlDatabase		m_db;
	QSqlQuery			m_query;
	SqlServerSettings	m_settings;
	QString				m_lastError;
	bool				m_connected, m_inTransaction;

	QHash<QString,int>					m_ontologyMap;
	QHash< int, QHash<QString,int> >	m_termMaps;
};

}; // Bio

#endif // SQL_SERVER_H